package com.example.demo.config.shiro.realme;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.example.demo.ResBean.constant.RedisConstant;
import com.example.demo.entity.sqlbean.Customer;
import com.example.demo.entity.sqlbean.JWTToken;
import com.example.demo.entity.sqlbean.Roles;
import com.example.demo.service.CustomerService;
import com.example.demo.service.UserService;
import com.example.demo.utils.RedisUtils;
import com.example.demo.utils.TokenUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
public class CustomRealm extends AuthorizingRealm {
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private CustomerService customerService;

    //根据token判断此Authenticator是否使用该realm
    //必须重写不然shiro会报错
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }


    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("授权~~~~~");
        String token = principals.toString();
        String username = TokenUtils.getUsername(token);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //查询数据库来获取用户的角色
        //
        info.addRole("user.getRoles()");
        //查询数据库来获取用户的权限
        info.addStringPermission("user.getPermission()");
        System.out.println(info.getStringPermissions());
        System.out.println(info.getRoles());
        return info;
    }

    /**
     * 用户认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("==========用户认证开始=============");
        //获取传入的token
        String jwtToken = (String) token.getCredentials();
        //获取用户名
        String username;
        if (StringUtils.isBlank(jwtToken)) {
            throw new AuthenticationException("token不存在.");
        }
        try {
            username = TokenUtils.getUsername(jwtToken);
            if (username == null) {
                throw new AuthenticationException("token中无用户名");
            }
        } catch (Exception e) {
            throw new AuthenticationException("token非法，不是规范的token");
        }
        String hashKey = RedisConstant.TOKEN_NAME + username;
        if (!RedisUtils.hHasKey(hashKey, jwtToken)) {
            throw new AuthenticationException("token不正确");
        }
        Customer customers = customerService.findCustomer(username);
//        Roles roles = userService.findUserByPhone(username);
        if (customers == null) {
            throw new AuthenticationException("该用户名不存在");
        }
        //开始认证，需要JwtToken未过期  且JwtToken和RedisToken中的时间戳一致
        boolean hasJwtToken = TokenUtils.verify(jwtToken);
        boolean hasRedisToken = RedisUtils.hHasKey(hashKey, jwtToken);
        if (hasJwtToken && hasRedisToken) {
            //判断AccessToken和refreshToken的时间节点是否一致
            long current = (long) RedisUtils.hget(hashKey, jwtToken);
            if (current == TokenUtils.getExpire(jwtToken)) {
                return new SimpleAuthenticationInfo(jwtToken, jwtToken, "customRealm");
            } else {
                throw new AuthenticationException("token已经失效，请重新登录！");
            }
        } else if (!hasJwtToken && hasRedisToken) {
            throw new TokenExpiredException("JwtToken失效,尝试刷新");
        } else {
            throw new AuthenticationException("token已经失效，请重新登录！");
        }
    }
}
